package org.example.myleet.p592;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

public class Solution {

    private static final BigInteger TWO = BigInteger.valueOf(2);
    private static final BigInteger THREE = BigInteger.valueOf(3);
    private static final BigInteger FIVE = BigInteger.valueOf(5);
    private static final BigInteger SEVEN = BigInteger.valueOf(7);

    public String fractionAddition(String expression) {
        //读取分数
        int i = 0;
        boolean add = true;
        char c = expression.charAt(i++);
        if (c == '-') {
            add = false;
        } else {
            --i;
        }
        List<Fraction> fractions = new ArrayList<>();
        BigInteger nominator = BigInteger.ZERO;
        BigInteger denominator;
        StringBuilder number = new StringBuilder();
        while (i < expression.length()) {
            c = expression.charAt(i);
            if (c == '-' || c == '+') {
                denominator = new BigInteger(number.toString());
                Fraction fraction = new Fraction(add, nominator, denominator);
                fractions.add(fraction);
                number.delete(0, number.length());
                add = c == '+';
            } else if (c == '/') {
                nominator = new BigInteger(number.toString());
                number.delete(0, number.length());
            } else {
                number.append(c);
            }
            ++i;
        }
        denominator = new BigInteger(number.toString());
        Fraction fraction = new Fraction(add, nominator, denominator);
        fractions.add(fraction);
        //每次融合两个分数
        Fraction res = fractions.get(0);
        for (i = 1; i < fractions.size(); ++i) {
            fraction = fractions.get(i);
            res = mergeFraction(res, fraction);
        }
        //输出结果
        StringBuilder result = new StringBuilder();
        if (!res.add) {
            result.append('-');
        }
        result.append(res.numerator.toString()).append('/').append(res.denominator.toString());
        return result.toString();
    }

    private Fraction mergeFraction(Fraction f1, Fraction f2) {
        //如果分母不相等，先将分数进行公倍化处理
        if (f1.denominator.compareTo(f2.denominator) != 0) {
            BigInteger temp = new BigInteger(f1.denominator.toString());
            f1.denominator = f1.denominator.multiply(f2.denominator);
            f1.numerator = f1.numerator.multiply(f2.denominator);
            f2.denominator = f2.denominator.multiply(temp);
            f2.numerator = f2.numerator.multiply(temp);
        }
        //如果两个分数符号相同，执行相加操作，否则执行相减操作
        if ((f1.add && f2.add) || (!f1.add && !f2.add)) {
            f1.numerator = f1.numerator.add(f2.numerator);
        } else {
            f1.numerator = f1.numerator.subtract(f2.numerator);
            if (f1.numerator.compareTo(BigInteger.ZERO) < 0) {
                //相减操作完之后可能会导致分子为负数，此时需要做符号取反
                f1.numerator = BigInteger.ZERO.subtract(f1.numerator);
                f1.add = !f1.add;
            }
        }
        //如果分子变成0，则按题目要求将分母变成1
        if (f1.numerator.compareTo(BigInteger.ZERO) == 0) {
            f1.denominator = BigInteger.ONE;
            f1.add = true;
        }
        //分子和分母进行公约化处理，分别将7、5、3、2这几个10以内的素数进行约分，使分数最简，以完成分数合并，结果保存在f1中返回
        while (f1.denominator.compareTo(SEVEN) >= 0 && f1.numerator.compareTo(SEVEN) >= 0 && f1.denominator.mod(SEVEN).compareTo(BigInteger.ZERO) == 0 && f1.numerator.mod(SEVEN).compareTo(BigInteger.ZERO) == 0) {
            f1.denominator = f1.denominator.divide(SEVEN);
            f1.numerator = f1.numerator.divide(SEVEN);
        }
        while (f1.denominator.compareTo(FIVE) >= 0 && f1.numerator.compareTo(FIVE) >= 0 && f1.denominator.mod(FIVE).compareTo(BigInteger.ZERO) == 0 && f1.numerator.mod(FIVE).compareTo(BigInteger.ZERO) == 0) {
            f1.denominator = f1.denominator.divide(FIVE);
            f1.numerator = f1.numerator.divide(FIVE);
        }
        while (f1.denominator.compareTo(THREE) >= 0 && f1.numerator.compareTo(THREE) >= 0 && f1.denominator.mod(THREE).compareTo(BigInteger.ZERO) == 0 && f1.numerator.mod(THREE).compareTo(BigInteger.ZERO) == 0) {
            f1.denominator = f1.denominator.divide(THREE);
            f1.numerator = f1.numerator.divide(THREE);
        }
        while (f1.denominator.compareTo(TWO) >= 0 && f1.numerator.compareTo(TWO) >= 0 && f1.denominator.mod(TWO).compareTo(BigInteger.ZERO) == 0 && f1.numerator.mod(TWO).compareTo(BigInteger.ZERO) == 0) {
            f1.denominator = f1.denominator.divide(TWO);
            f1.numerator = f1.numerator.divide(TWO);
        }
        return f1;
    }

    static class Fraction {
        boolean add;
        BigInteger numerator;
        BigInteger denominator;

        public Fraction(boolean add, BigInteger numerator, BigInteger denominator) {
            this.add = add;
            this.numerator = numerator;
            this.denominator = denominator;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder("Fraction{");
            sb.append("operator=").append(add ? '+' : '-').append(numerator).append('/').append(denominator);
            sb.append('}');
            return sb.toString();
        }
    }
}
